package com.simba.server.framedecoder.decoders;

import com.simba.common.decoder.Decoder;
import com.simba.common.frameserver.FrameChannelManager;
import com.simba.common.jsonserver.JsonChannelManager;
import com.simba.common.log.LogUtil;
import com.simba.common.utils.FrameUtils;
import com.simba.common.utils.StringUtil;
import com.simba.server.commands.impl.record.RecordMachineOpsCmd;
import com.simba.server.commands.impl.update.RenewBasicConfigCmd;
import com.simba.server.components.*;
import com.simba.server.components.data.BasicConfig;
import com.simba.server.components.data.MachineOps;
import com.simba.server.components.data.SorterInfo;
import org.apache.log4j.Logger;
import org.jboss.netty.channel.Channel;
import org.json.JSONObject;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author create by kavin
 * @date 2020/9/10 15:34
 */
public class KeepAliveDecoder implements Decoder {
    private static class RockerKeepAliveDecoderHolder
    {
        private static final KeepAliveDecoder INSTANCE = new KeepAliveDecoder();
    }

    public static final String NAME = "Wheel-KeepAlive-Decoder";
    protected final static Logger logger = Logger.getLogger(KeepAliveDecoder.class);
    private static final int SORTER_NUM_POSITION = 3;
    private static final int SYS_STATUS_POSITION = 5;
    private static final int OBR_POSITION = 6;

    private static final int MACHINE_STARTED = 1;
    private static final int MACHINE_STOPPED = 2;
    private static final int MACHINE_WAIT = 4;
    private ConcurrentHashMap<String, Integer> sorterStatusMap = new ConcurrentHashMap<>();

    public static KeepAliveDecoder getInstance()
    {
        return RockerKeepAliveDecoderHolder.INSTANCE;
    }

    private KeepAliveDecoder()
    {

    }

    @Override
    public void doDecode(Channel channel, Object message) {
        try {
            ChannelsManager.getInstance().updateClient(channel);

            byte[] content = (byte[]) message;
            LogUtil.LogInfo(logger,"收到plc来的心跳报文"+ StringUtil.byteToHexString(content));
            int sorterID = FrameUtils.getInstance().getUnsignedShortBigEndian(SORTER_NUM_POSITION, content);

            SorterInfo wheelSorterInfo = SorterManager.getInstance().getWheelSorterByID(String.valueOf(sorterID));
            if (wheelSorterInfo == null)
            {
                return;
            }
            wheelSorterInfo.setChannel(channel);

            int sorterStatus = content[SYS_STATUS_POSITION];

            wheelSorterInfo.setSorterId(String.valueOf(sorterID));
            wheelSorterInfo.setSorterStatus(String.valueOf(sorterStatus));
            wheelSorterInfo.setObrNum(0);
            wheelSorterInfo.setEmergencyNum(0);
            wheelSorterInfo.setLineNum(0);
            doMachineStatus(wheelSorterInfo.getSorterId(), sorterStatus);

            int position = OBR_POSITION;

            position = this.handlerObrStatus(content, wheelSorterInfo, position);

            position = this.handlerEmergencyStatus(content, wheelSorterInfo, position);

            this.sendToDWSClient(wheelSorterInfo);

             this.handlerLineStatus(content, wheelSorterInfo, position);

            this.sendContentEchoToPLC(channel, content);
        }catch (Exception e){
            LogUtil.LogError(logger, "[KeepAliveDecoder.doDecode] Catch Exception : " + e.toString());
        }
    }

    @Override
    public String getName() {
        return NAME;
    }

    private int handlerObrStatus(byte[] content, SorterInfo wheelSorterInfo, int position)
    {
        String obrtatus = "";
        int obrNumPosition = position;
        position = obrNumPosition + 2;
        int obrNum = FrameUtils.getInstance().getUnsignedShortBigEndian(obrNumPosition, content);

        for (int i = 1; i <= obrNum; i++)
        {
            int intStatus = content[position];
            obrtatus += (intStatus + ",");
            position++;
        }

        if (obrtatus.length() >= 2)
        {
            obrtatus = obrtatus.substring(0, obrtatus.length() - 1);
            wheelSorterInfo.setObrNum(obrNum);
            wheelSorterInfo.setObrStatus(obrtatus);
        }
        return position;
    }

    private int handlerEmergencyStatus(byte[] content, SorterInfo wheelSorterInfo, int position)
    {
        String emergencyStatus = "";
        int emergencyNumPosition = position;
        position = emergencyNumPosition + 2;
        int emergencyNum = FrameUtils.getInstance().getUnsignedShortBigEndian(emergencyNumPosition, content);
        for (int i = 1; i <= emergencyNum; i++)
        {
            int intStatus = content[position];
            emergencyStatus += (intStatus + ",");
            position++;
        }

        if (emergencyStatus.length() >= 2)
        {
            emergencyStatus = emergencyStatus.substring(0, emergencyStatus.length() - 1);
            wheelSorterInfo.setEmergencyNum(emergencyNum);
            wheelSorterInfo.setEmergencyStatus(emergencyStatus);
        }
        return position;
    }

    private int handlerLineStatus(byte[] content, SorterInfo wheelSorterInfo, int position)
    {
        String lineStatus = "";
        int lineNumPosition = position;
        position = lineNumPosition + 2;
        int lineNum = FrameUtils.getInstance().getUnsignedShortBigEndian(lineNumPosition, content);
        for (int i = 1; i <= lineNum; i++)
        {
            int intStatus = content[position];
            lineStatus += (intStatus + ",");
            position++;
        }
        if (lineStatus.length() >= 2)
        {
            lineStatus = lineStatus.substring(0, lineStatus.length() - 1);
            wheelSorterInfo.setLineNum(lineNum);
            wheelSorterInfo.setLineStatus(lineStatus);
        }
        return position;
    }

    public void sendContentEchoToPLC(Channel channel, byte[] content)
    {
        if (content == null || content.length < 2)
        {
            return;
        }
        content[0] = 0x02;
        content[1] = 0x01;
        FrameChannelManager.getInstance().commitResponse(channel, content, false);
    }

    private void recordMachineAction(String workerNo, int opsType, String opsDesc)
    {
        try
        {
            MachineOps machineOps = new MachineOps();
            machineOps.setWorkerNo(workerNo);
            machineOps.setOpsType(opsType);
            machineOps.setOpsDesc(opsDesc);

            CommandExecutor.executorSqlCommand(RecordMachineOpsCmd.NAME, machineOps,false);
        }
        catch (Exception ex)
        {
            LogUtil.LogError(MachineStatusDecoder.logger,
                    "Record machine action catch exception : " + ex.getMessage());
        }
    }

    private void doMachineStatus(String workerNo, int machineStatus){
        if (sorterStatusMap.containsKey(workerNo)){
            if (sorterStatusMap.get(workerNo).equals(machineStatus)){
                return;
            }
        }
        sorterStatusMap.put(workerNo, machineStatus);
        SortControllerManager.getInstance().onMachineStateMessage(machineStatus);
        switch (machineStatus)
        {
            case MACHINE_STARTED:
                this.recordMachineAction(workerNo, MACHINE_STARTED, "started");
                break;
            case MACHINE_STOPPED:
                this.recordMachineAction(workerNo, MACHINE_STOPPED, "stopped");
                break;
            case MACHINE_WAIT:
                this.recordMachineAction(workerNo, MACHINE_WAIT, "emergency");
                break;
            default:
                break;
        }
    }

    private void sendToDWSClient(SorterInfo wheelSorterInfo)
    {
        JSONObject sendObj = new JSONObject();
        sendObj.put("ServiceName", "WheelStatus");
        sendObj.put("SorterID", wheelSorterInfo.getSorterId());
        sendObj.put("SorterStatus", wheelSorterInfo.getSorterStatus());
        sendObj.put("SorterModel", wheelSorterInfo.getSorterModel());
        sendObj.put("EmergencyStatus", wheelSorterInfo.getEmergencyStatus());
        sendObj.put("OBRStatus", wheelSorterInfo.getObrStatus());
        sendObj.put("LineStatus", wheelSorterInfo.getLineStatus());

        LogUtil.LogInfo(logger,"发给监控"+sendObj.toString());
        Channel[] channels = JsonChannelManager.getInstance().getChannelList();

        for (Channel tmpChannel : channels) {
            if (tmpChannel == null) {
                continue;
            }
            JsonChannelManager.getInstance().commitResponse(tmpChannel, sendObj.toString().getBytes(), false);
        }


    }
}
